# 使用@property

# 在绑定属性时，如果我们直接把属性暴露出去，虽然写起来很简单，但是，没办法检查参数，导致可以把成绩随便改
class Student(object):
    pass

s = Student()
s.score = 9999

'''
这显然不合逻辑。为了限制score的范围，可以通过一个set_score()方法来设置成绩，再通过一个get_score()的方法来获取成绩，这样，在 set_score()方法里面
就可以检查参数
'''
class Student(object):
    def get_score(self):
        return self.score

    def set_score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self.score = value
# 现在，对任意的 Student 实例进行操作，就不能随心所欲的设置score了
s = Student()
s.set_score(60)
print(s.get_score())
# s.set_score(9999) # 错误，超出范围
print(s.get_score())

print('-' * 100)

# 使用@property
'''
但是，上面的调用方法又略显复杂，没有直接用属性这么直接简单

有没有既能检查参数，又可以用类似属性这样简单的方式来访问类的变量呢？对于追求完美的Python程序员来说，这是必须要做到的

还记得装饰器（decorator）可以给函数加上功能吗？对于类的方法，装饰器一样起作用，python内置的 @property装饰器就是负责吧一个方法变成属性调用的
'''

class Student(object):
    @property   # 相当于 getter
    def score(self):
        return self._score

    @score.setter # 相当于 setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value
s = Student()
s.score = 66 # OK，实际转化为s.score(60)
print(s.score) # OK，实际转化为s.score()
# s.score = 8888 # 会报错，超过范围
